#include "symtable.hpp"

SymbolTable* SymbolTable::builtin_symtable = new SymbolTable();

void SymbolTable::add_name(const string& name, Type* type) {
    _name_map[name] = _name_map.size();
    _name_type[name] = type;
    _names.push_back(name);
}

int SymbolTable::get_name_index(const string& name) {
    auto it = _name_map.find(name);
    if (it != _name_map.end()) {
        return it->second;
    }

    return -1;
}

Type* SymbolTable::get_name_type(const string& name) {
    auto it = _name_type.find(name);
    if (it != _name_type.end()) {
        return it->second;
    }

    return nullptr;
}

int SymbolTable::get_var_name_index(const string& name) {
    auto it = _var_name_map.find(name);
    if (it != _var_name_map.end()) {
        return it->second;
    }

    return -1;
}

Type* SymbolTable::get_var_name_type(const string& name) {
    auto it = _var_name_type.find(name);
    if (it != _var_name_type.end()) {
        return it->second;
    }

    return nullptr;
}

void SymbolTable::add_var_name(const string& name, Type* type) {
    _var_name_map[name] = _var_name_map.size();
    _var_name_type[name] = type;
    _var_names.push_back(name);
}

int SymbolTable::get_free_var_index(const string& name) {
    auto it = _free_map.find(name);
    if (it != _free_map.end()) {
        return it->second;
    }

    return -1;
}

Type* SymbolTable::get_free_var_type(const string& name) {
    auto it = _free_type.find(name);
    if (it != _free_type.end()) {
        return it->second;
    }

    return nullptr;
}

void SymbolTable::add_free_var(const string& name, Type* type) {
    _free_map[name] = _free_map.size();
    _free_type[name] = type;
    _freevars.push_back(name);
}

int SymbolTable::get_cell_var_index(const string& name) {
    auto it = _cell_map.find(name);
    if (it != _cell_map.end()) {
        return it->second;
    }

    return -1;
}

Type* SymbolTable::get_cell_var_type(const string& name) {
    auto it = _cell_type.find(name);
    if (it != _cell_type.end()) {
        return it->second;
    }

    return nullptr;
}

void SymbolTable::add_cell_var(const string& name) {
    _cell_map[name] = _cell_map.size();
    _cell_type[name] = _var_name_type[name];
    _cellvars.push_back(name);

    int index = get_var_name_index(name);
    if (index >= _arg_count) {
        for (int i = index; i < _var_names.size() - 1; i++) {
            _var_names[i] = _var_names[i+1];
            _var_name_map[_var_names[i]] = _var_name_map[_var_names[i]] - 1;
        }
        _var_names.pop_back();
        _var_name_map.erase(name);
        _var_name_type.erase(name);
    }
}

void SymbolTable::load_builtin() {
    add_name("True", BoolType::get_instance());
    add_name("False", BoolType::get_instance());
}

